package com.future.common.jfinalcustom;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.jfinal.kit.StrKit;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;

public class MyQrCodeRender extends Render{
	protected String content;
	protected int width;
	protected int height;
	protected ErrorCorrectionLevel errorCorrectionLevel;
	protected String underWords;
	protected String upperWords;
		
	/**
	 * 支持底部文字和顶部文字
	 * @param content
	 * @param width
	 * @param height
	 * @param errorCorrectionLevel
	 * @param upperWords
	 * @param underWords
	 */
	public MyQrCodeRender(String content, int width, int height, char errorCorrectionLevel, String upperWords,
			String underWords) {
		super();
		init(content, width, height, errorCorrectionLevel, underWords, upperWords);
	}

	protected void init(String content, int width, int height, char errorCorrectionLevel, String underWords, String uppderWords) {
		if (errorCorrectionLevel == 'H') {
			init(content, width, height, ErrorCorrectionLevel.H, underWords, uppderWords);
		} else if (errorCorrectionLevel == 'Q') {
			init(content, width, height, ErrorCorrectionLevel.Q, underWords, uppderWords);
		} else if (errorCorrectionLevel == 'M') {
			init(content, width, height, ErrorCorrectionLevel.M, underWords, uppderWords);
		} else if (errorCorrectionLevel == 'L') {
			init(content, width, height, ErrorCorrectionLevel.L, underWords, uppderWords);
		} else {
			throw new IllegalArgumentException("errorCorrectionLevel 纠错级别参数值，从高到低必须为： 'H'、'Q'、'M'、'L'");
		}
	}
	protected void init(String content, int width, int height, ErrorCorrectionLevel errorCorrectionLevel, String underWords, String upperWords) {
		if (StrKit.isBlank(content)) {
			throw new IllegalArgumentException("content 不能为空");
		}
		if (width < 0 || height < 0) {
			throw new IllegalArgumentException("width 与 height 不能小于 0");
		}
		this.content = content;
		this.width = width;
		this.height = height;
		this.errorCorrectionLevel = errorCorrectionLevel;
		this.underWords = (underWords == null ? "" : underWords);
		this.upperWords = (upperWords == null ? "" : upperWords);
	}
	
	@Override
	public void render() {
		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		response.setContentType("image/png");

		Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
		hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
		hints.put(EncodeHintType.MARGIN, 3); // 去掉白色边框，极度重要，否则二维码周围的白边会很宽
		if (errorCorrectionLevel != null) {
			hints.put(EncodeHintType.ERROR_CORRECTION, errorCorrectionLevel);
		}

		try {
			// MultiFormatWriter 可支持多种格式的条形码，在此直接使用 QRCodeWriter，通过查看源码可知少创建一个对象
			// BitMatrix bitMatrix = new MultiFormatWriter().encode(content,
			// BarcodeFormat.QR_CODE, width, height, hints);

			QRCodeWriter writer = new QRCodeWriter();
			BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
			BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
			// 创建一个带透明色的BufferedImage对象
			BufferedImage outImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
			Graphics2D outg = outImage.createGraphics();
			setGraphics2D(outg);

			// 画二维码到新的面板
			outg.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
			// 画文字到新的面板
			Color color = new Color(0, 0, 0);
			outg.setColor(color);
			// 字体、字型、字号
			outg.setFont(new Font("微软雅黑", Font.PLAIN, 14));
			// 文字长度
			int strUnderWidth = outg.getFontMetrics().stringWidth(underWords);
			// 总长度减去文字长度的一半 （居中显示）
			int wordUnderStartX = (width - strUnderWidth) / 2;
			// height + (outImage.getHeight() - height) / 2 + 12
			int wordUnderStartY = height - 2;
			
			int strUpperWidth = outg.getFontMetrics().stringWidth(upperWords);
			// 总长度减去文字长度的一半 （居中显示）
			int wordUpperStartX = (width - strUpperWidth) / 2;
			// 画文字
			int wordUpperStartY = 14;
			outg.drawString(underWords, wordUnderStartX, wordUnderStartY);
			outg.drawString(upperWords, wordUpperStartX, wordUpperStartY);
			outg.dispose();
			outImage.flush();
			// 经测试 200 X 200 大小的二维码使用 "png" 格式只有 412B，而 "jpg" 却达到 15KB
			ImageIO.write(outImage, "png", response.getOutputStream());
		} catch (IOException e) { // ClientAbortException、EofException 直接或间接继承自
									// IOException
			String name = e.getClass().getSimpleName();
			if ("ClientAbortException".equals(name) || "EofException".equals(name)) {
			} else {
				throw new RenderException(e);
			}
		} catch (Exception e) {
			throw new RenderException(e);
		}
	}
	   /**
	    * 设置 Graphics2D 属性  （抗锯齿）
	    * @param graphics2D
	    */
	   private static void setGraphics2D(Graphics2D graphics2D){
	      graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
	      graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
	      Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
	      graphics2D.setStroke(s);
	   }
	
}
